[% setvar title Replace default filehandle/select with $DEFOUT, $DEFERR, $DEFIN %]
<div id="archive-notice">
    <h3>This file is part of the Perl 6 Archive</h3>
    <p>To see what is currently happening visit <a href="http://www.perl6.org/">http://www.perl6.org/</a></p>
</div>
<div class='pod'>
<a name='TITLE'></a><h1>TITLE</h1>
<p>Replace default filehandle/select with $DEFOUT, $DEFERR, $DEFIN</p>
<a name='VERSION'></a><h1>VERSION</h1>
<pre>  Maintainer: Nathan Wiger &lt;<a href='mailto:nate@wiger.org'>nate@wiger.org</a>&gt;
  Date: 17 Aug 2000
  Last Modified: 13 Sep 2000
  Mailing List: <a href='mailto:perl6-language-io@perl.org'>perl6-language-io@perl.org</a>
  Number: 129
  Version: 2
  Status: Frozen</pre>
<a name='ABSTRACT'></a><h1>ABSTRACT</h1>
<p>A basic Perl 5 implementation can be found as IO::Default at
<a href='http://www.perl.com/CPAN/authors/id/N/NW/NWIGER/IO-Default-1.03.tar.gz' target='_blank'>www.perl.com</a></p>
<p>The concept of a &quot;default filehandle&quot; is nebulous. Many users
can't get their heads around it, and even if they can, it is
still kind of mysterious.</p>
<p>This proposes that the &quot;default filehandle&quot; and 1-arg select
be dropped from Perl 6 and replaced with the variable <code>$DEFOUT</code>,
the Default Output handle. Whatever this variable contains will
be what is printed to by default. This will make default output
consistent with the <code>fileobject</code> approach and also other Perl special
variables.</p>
<p>In addition, this RFC proposes the addition of two new variables,
<code>$DEFERR</code> and <code>$DEFIN</code>, the Default Error and Default Input handles.
These can be used to redirect default error output and default input,
for added flexibility.</p>
<a name='NOTES ON FREEZE'></a><h1>NOTES ON FREEZE</h1>
<p>Some discussion, particularly by Jon Ericson, was recorded on this RFC.
Most of it boiled down to clarifications of issues. Jon questioned the
usefulness of <code>$DEFERR</code>, but I think it serves a very useful purpose
since it allows you to redirect warnings (which would be directed to
<code>$DEFERR</code>) without affecting statements that print to <code>$STDERR</code>
explicitly. There is also very nice symmetry between the <code>DEF*</code> default
handles and the <code>STD*</code> standard handles.</p>
<a name='DESCRIPTION'></a><h1>DESCRIPTION</h1>
<a name='$DEFOUT'></a><h2>$DEFOUT</h2>
<p>Currently, the &quot;default filehandle&quot; (&quot;DF&quot; to save typing) is
hidden. It can only be accessed or changed via the <code>select</code>
function.</p>
<p>With the advent of full-featured <b>fileobjects</b>, having a
special DF is unnecessary. Instead, we simply make a variable,
called <code>$DEFOUT</code>, which is where unspecified output is sent.
Changing the DF is done through simple variable assignment.</p>
<p>Below are some examples of Perl 5 versus Perl 6 syntax:</p>
<pre>   Perl 5                    Perl 6 
   -----------------------   --------------------------
   select FILE;              $DEFOUT = $FILE;
   
   $oldh = select;           $oldh = $DEFOUT;

   $oldh = select FILE;      $oldh = $DEFOUT;
                             $DEFOUT = $FILE;

   $| = 1                    $DEFOUT-&gt;autoflush(1); # or:
                             autoflush $DEFOUT;     # ?</pre>
<p>What advantages besides a new syntax are there? Several:</p>
<pre>   1. The rule is easier. No DF, just &quot;everything goes
      to $DEFOUT by default&quot;. Changing this is done by
      simple assignment.

   2. It's less hidden. Most everything else in Perl is
      handled in variables such as @INC, %ENV, and so
      forth. This makes filehandles that much easier.

   3. Access to object methods is available directly on
      the current filehandle object via $DEFOUT-&gt;method,
      eliminating the need for $|, $/, $\, and so on.[1]

   4. No more 1-arg select vs. 4-arg select confusion.</pre>
<p>Whatever object <code>$DEFOUT</code> contains is what default output
goes to and what the object methods work on. There is no
mysterious hidden DF. <code>$DEFOUT</code> works just like other
variables.</p>
<a name='$DEFERR'></a><h2>$DEFERR</h2>
<p>The new <code>$DEFERR</code> variable can be used to easily redirect
error output as well, something you often want to do if
you're not attached to a tty. However, having a script that
runs easily in both environments is tricky in Perl 5:</p>
<pre>   if ( $have_a_tty ) {
      print STDERR &quot;Warning: Bad stuff\n&quot;;
   } else {
      print ERRORLOG &quot;Warning: Bad stuff\n&quot;;
   }</pre>
<p>You have to put checks similar to this for many functions
and different situations. Plus, it doesn't catch <code>carp</code> or
<code>die</code> calls embedded in modules, meaning that you will
always lose some important error output.</p>
<p>With <code>$DEFERR</code>, all error functions are set to act on it
instead of <code>$STDERR</code> by default. So, the Perl 6 version
of the above is replaced by a single simple line of code
at the top of your main program:</p>
<pre>   $DEFERR = $ERRORLOG unless $have_a_tty;</pre>
<p>Presto, all error-related functions now redirect to your
error log automatically. All through simple assignment.</p>
<p>As Jon Ericson pointed out, this can be accomplished in a similar vein
currently by reopening STDERR onto another file, or by using typeglob
aliases to other open filehandles. However, it does not allow you to mix
calls to files and STDERR like you can with files and STDOUT.</p>
<p>Using $DEFERR allows you to do so if you have functions that you want to
explicitly print to <code>$STDERR</code>:</p>
<pre>   warn &quot;Badness!&quot;;          # goes to $DEFERR
   print $STDERR &quot;Badness!&quot;  # explicitly to $STDERR</pre>
<p>This is not easy to do in Perl 5.[2] This is quite useful if, for
example, you want a cron job to log all error either to the screen or
log files but always print out the same message at the end:</p>
<pre>   $DEFERR = $ERRORLOG unless $have_a_tty;
   # ...
   warn &quot;Bad stuff: $!&quot;;     # to $DEFERR
   # ...
   carp &quot;This too: $!&quot;;      # ditto
   # ...
   if ( $really_bad ) {
       print $STDERR &quot;Fatal error! Check the logfiles!\n&quot;;
       exit 1;
   }</pre>
<p>That way you'd get a cron-generated message (perhaps to your pager) that
was brief, while the code could still send other errors to either the
screen or logfile automatically.</p>
<a name='$DEFIN'></a><h2>$DEFIN</h2>
<p>The new <code>$DEFIN</code> accomplishes a similar thing, but with input.
Currently, the special &lt;&gt; filehandle iterates through the command-line
files stored in <code>@ARGV</code>. You can also use it to open <code>STDIN</code>, but only
if <code>@ARGV</code> is empty (it unshifts '-' onto <code>@ARGV</code>). However, &lt;&gt; is
potentially more useful as a default input filehandle, much like a
simple &quot;print&quot; uses $_ for its default output:</p>
<pre>   @data = &lt;&gt;;       # read from $DEFIN</pre>
<p>The new <code>$DEFIN</code> variable becomes what is read from when &lt;&gt; is used. It
should point to <code>$STDIN</code> by default. This allows greater flexibility,
more consistency with operators like print, and doesn't require us to
reopen filehandles to get to different input sources:</p>
<pre>   # Figure out our input source based on what's open
   $DEFIN = $infile || $instream || $STDIN;
   @data = &lt;&gt;;</pre>
<p>This allows valuable compartmentalization of code. The
simple &lt;&gt; construct is now a synonym for <code>$DEFIN</code>. This
means that you can place something like the <code>@data = </code>&lt;&gt;
line in a module, and allow the top-level code to change
the data source based on a simple assignment. You no
longer have to pass filehandles into functions or do
complex <code>tie</code> manuevers to gain this ability.</p>
<p>Plus, with <code>$DEFIN</code>, if you have a routine that must
read from <code>$STDIN</code>, you can still do so easily by
explicitly saying:</p>
<pre>   $yes_or_no = &lt;$STDIN&gt;;   # explicitly from $STDIN
   @data = &lt;&gt;;              # read from $DEFIN</pre>
<p>To retain the special behavior currently with &lt;&gt;, it is recommended that
Perl 6 require explicit use of <code>$ARGV</code>:</p>
<pre>   while (&lt;$ARGV&gt;) { }      # iterate through @ARGV</pre>
<p>This has the benefit that it makes it more obvious that we're iterating
through <code>@ARGV</code>. It also means that you can use &lt;&gt; to grab <code>STDIN</code>
while retaining the values in &lt;@ARGV&gt;, which is not possible currently.</p>
<a name='Naming'></a><h2>Naming</h2>
<p>The naming of the variables was chosen to make them
consistent with the Standard IO handles <code>$STDIN</code>,
<code>$STDOUT</code>, and <code>$STDERR</code>.</p>
<a name='IMPLEMENTATION'></a><h1>IMPLEMENTATION</h1>
<p>Remove 1-arg <code>select</code>. Make sure p52p6 translates <code>select</code>
to the new syntax.</p>
<p>Create <code>$DEFOUT</code> variable and reset output functions to act on
<code>$DEFOUT</code> instead of the default filehandle. <code>$DEFOUT</code> should point to
the system's stdout by default, just like the default filehandle does
currently.</p>
<p>Add <code>$DEFERR</code> variable and reset error functions (such as warn and die)
to print to <code>$DEFERR</code> instead of <code>STDERR</code>. <code>$DEFERR</code> should point to
the system's stderr by default, just like STDERR.</p>
<p>Add <code>$DEFIN</code> and change &lt;&gt; and other default input to work on
<code>$DEFIN</code>. <code>$DEFIN</code> should point to the system's stdin by default.</p>
<p>A basic Perl 5 implementation can be found as IO::Default at
<a href='http://www.perl.com/CPAN/authors/id/N/NW/NWIGER/IO-Default-1.03.tar.gz' target='_blank'>www.perl.com</a></p>
<a name='MIGRATION'></a><h1>MIGRATION</h1>
<p>The 1-arg <code>select</code> syntax would have to be translated to something
like:</p>
<pre>   $DEFOUT = $FILE;        # was select(FILE);</pre>
<p>Since the only other thing that would really change would be the meaning
of &lt;&gt; in loops, p52p6 would have to translate while(&lt;&gt;) to:</p>
<pre>   while (&lt;$ARGV&gt;) {  }</pre>
<p>However, when used outside of a loop, like so:</p>
<pre>   @file = &lt;&gt;;</pre>
<p>No translation would have to take place since the usage would likely be
a shortcut to <code>STDIN</code> (which would be retained since &lt;&gt; == <code>$DEFIN</code> ==
<code>$STDIN</code> by default).</p>
<a name='NOTES'></a><h1>NOTES</h1>
<p>[1] This RFC does not take a firm stance on eliminating
$|, $/, $\, and friends. However, this approach to handling
default input and output does mean they are no longer needed.
I do think they should go, but this RFC does not require it.</p>
<p>[2] It is possible in a way, but you can't print to STDERR explicitly,
and you have to use a series of open calls. Better to just send it to
the default error handle, whatever that may contain.</p>
<a name='REFERENCES'></a><h1>REFERENCES</h1>
<p>RFC 14: Modify open() to support FileObjects and Extensibility</p>
<p>RFC 30: STDIN, STDOUT, and STDERR should be renamed</p>
<p><a href='http://www.mail-archive.com/perl6-language-io@perl.org/msg00182.html' target='_blank'>www.mail-archive.com</a></p>
<p><a href='http://www.mail-archive.com/perl6-language-io@perl.org/msg00228.html' target='_blank'>www.mail-archive.com</a></p>
</div>
